home *** CD-ROM | disk | FTP | other *** search
- ///////////////////////////////////////////////////////////////////////////////
- // $Id: m68000.cxx,v 1.3 1995/06/30 00:06:57 bmott Exp $
- ///////////////////////////////////////////////////////////////////////////////
- // m68000.cxx
- //
- // Motorola 68000 microprocessor class
- //
- // Sim68000 "Motorola 68000 Simulator"
- // Copyright (c) 1993
- // By: Bradford W. Mott
- // October 31,1993
- //
- ///////////////////////////////////////////////////////////////////////////////
- // $Log: m68000.cxx,v $
- // Revision 1.3 1995/06/30 00:06:57 bmott
- // Changed interrupt servicing so that breakpoints at the service routine
- // will operate correctly
- //
- // Revision 1.2 1994/09/22 00:12:48 bmott
- // Added code to handle the BREAK state
- //
- // Revision 1.1 1994/02/18 20:04:25 bmott
- // Initial revision
- //
- ///////////////////////////////////////////////////////////////////////////////
-
- #include "Tools.hxx"
- #include "m68000.hxx"
-
- RegisterData m68000::register_data[] = {
- {"D0", 0xffffffff, "Data Register 0"},
- {"D1", 0xffffffff, "Data Register 1"},
- {"D2", 0xffffffff, "Data Register 2"},
- {"D3", 0xffffffff, "Data Register 3"},
- {"D4", 0xffffffff, "Data Register 4"},
- {"D5", 0xffffffff, "Data Register 5"},
- {"D6", 0xffffffff, "Data Register 6"},
- {"D7", 0xffffffff, "Data Register 7"},
- {"A0", 0xffffffff, "Address Register 0"},
- {"A1", 0xffffffff, "Address Register 1"},
- {"A2", 0xffffffff, "Address Register 2"},
- {"A3", 0xffffffff, "Address Register 3"},
- {"A4", 0xffffffff, "Address Register 4"},
- {"A5", 0xffffffff, "Address Register 5"},
- {"A6", 0xffffffff, "Address Register 6"},
- {"A7", 0xffffffff, "Address Register 7 (User Stack Pointer)"},
- {"A7'" ,0xffffffff, "Address Register 7 (Supervisor Stack Pointer)"},
- {"PC", 0xffffffff, "Program Counter"},
- {"SR", 0x0000ffff, "Status Register: T-S--III---XNZVC\n T: Trace Mode\n S: Supervisory Mode\n I: Interrupt Mask Level\n X: Extend\n N: Negative\n Z: Zero\n V: Overflow\n C: Carry"}
- };
-
-
- ///////////////////////////////////////////////////////////////////////////////
- // The m68000 Class constructor
- ///////////////////////////////////////////////////////////////////////////////
- m68000::m68000(AddressSpace *addr)
- : BasicCPU("68000", // Name of the CPU
- 1, // Granularity in bytes
- 1, // Number of addr spaces
- addr, // Array of addr spaces
- "{InstructionAddress 8} " // Execution trace record
- "{Mnemonic 35}",
- "InstructionAddress Mnemonic" // Default trace entries
- ),
- number_of_registers(19), // Number of registers
- C_FLAG(0x0001), // SR flags
- V_FLAG(0x0002),
- Z_FLAG(0x0004),
- N_FLAG(0x0008),
- X_FLAG(0x0010),
- I0_FLAG(0x0100),
- I1_FLAG(0x0200),
- I2_FLAG(0x0400),
- S_FLAG(0x2000),
- T_FLAG(0x8000),
- D0_INDEX(0), // Register Indices
- A0_INDEX(8),
- USP_INDEX(15),
- SSP_INDEX(16),
- PC_INDEX(17),
- SR_INDEX(18),
- EXECUTE_OK(0), // Execution return codes
- EXECUTE_PRIVILEGED_OK(1),
- EXECUTE_BUS_ERROR(2),
- EXECUTE_ADDRESS_ERROR(3),
- EXECUTE_ILLEGAL_INSTRUCTION(4),
- NORMAL_STATE(0), // Processor states
- HALT_STATE(1),
- STOP_STATE(2),
- BREAK_STATE(3)
- {
- // Buld the decode cache if necessary
- if(decode_cache_table == (void*)0)
- {
- // Allocate memory for the decode cache table
- decode_cache_table=new ExecutionPointer[65536];
-
- // Set all cache entries to invalid (NULL)
- for(int t=0;t<65536;++t)
- decode_cache_table[t]=(void*)0;
- }
-
- // Allocate array for register values
- register_value=new unsigned long[number_of_registers];
-
- // Clear the registers
- for(int t=0;t<number_of_registers;++t)
- register_value[t]=0;
-
- // Reset the system
- Reset();
-
- my_interrupt=-1;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // The m68000 Class destructor
- ///////////////////////////////////////////////////////////////////////////////
- m68000::~m68000()
- {
- // Free the register value array
- delete[] register_value;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // Preform a system reset
- ///////////////////////////////////////////////////////////////////////////////
- void m68000::Reset()
- {
- unsigned int pc, ssp;
-
- // Reset all of the device's attached to the processor
- address_space->Reset();
-
- // Set the Status register to its reset value
- register_value[SR_INDEX] = S_FLAG | I0_FLAG | I1_FLAG | I2_FLAG;
-
- // Fetch the Supervisor Stack Pointer from location $00000000
- if(Peek(0x00000000, ssp, LONG) != EXECUTE_OK)
- SetRegister(SSP_INDEX, 0, LONG);
- else
- SetRegister(SSP_INDEX, ssp, LONG);
-
- // Fetch the Program Counter from location $00000004
- if(Peek(0x00000004, pc, LONG) != EXECUTE_OK)
- SetRegister(PC_INDEX, 0, LONG);
- else
- SetRegister(PC_INDEX, pc, LONG);
-
- // Put the processor in normal instrution execution mode
- processor_state=NORMAL_STATE;
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // Return the value in the program counter
- ///////////////////////////////////////////////////////////////////////////////
- unsigned long m68000::ValueOfProgramCounter()
- {
- return(register_value[PC_INDEX]);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // Build the statistics list for the StatisticalInformationList object
- ///////////////////////////////////////////////////////////////////////////////
- void m68000::BuildStatisticalInformationList(StatisticalInformationList*)
- {
- // We're not keeping up with any stupid statistics :-}
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // Set the named register to the given value
- ///////////////////////////////////////////////////////////////////////////////
- void m68000::SetRegister(String name, String hex_value)
- {
- unsigned int value;
-
- value=StringToInt(hex_value);
-
- for(int t=0;t<number_of_registers;++t)
- {
- if(name==register_data[t].name)
- {
- register_value[t]=(value & register_data[t].mask);
- break;
- }
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // Build the register list for the RegisterInformationList object
- ///////////////////////////////////////////////////////////////////////////////
- void m68000::BuildRegisterInformationList(RegisterInformationList *list)
- {
- int t;
- String value;
-
- for(t=0;t<number_of_registers;++t)
- {
- if(t!=SR_INDEX)
- value=IntToString((register_value[t]®ister_data[t].mask),8);
- else
- value=IntToString((register_value[t]®ister_data[t].mask),4);
-
- list->Append(register_data[t].name,value,register_data[t].description);
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // Execute the next instruction
- ///////////////////////////////////////////////////////////////////////////////
- const char* m68000::ExecuteInstruction(String& trace_record, int trace_flag)
- {
- unsigned int opcode;
- ExecutionPointer exec_function;
- int status;
-
- // Add instruction address to the trace record
- if(trace_flag)
- {
- trace_record="{InstructionAddress ";
- trace_record+=IntToString(register_value[PC_INDEX],8);
- trace_record+="} ";
- }
-
- // Make sure the CPU hasn't been halted
- if(processor_state!=HALT_STATE)
- {
- int serviceFlag;
-
- // Service any pending interrupts
- status = ServiceInterrupts(serviceFlag);
-
- // Only execute an instruction if we didn't service an interrupt
- if((!serviceFlag) && (status == EXECUTE_OK))
- {
- // Make sure the CPU isn't stopped waiting for exceptions
- if(processor_state!=STOP_STATE)
- {
- // Fetch the next instruction
- if((status=Peek(register_value[PC_INDEX],opcode,WORD))==EXECUTE_OK)
- {
- register_value[PC_INDEX]+=2;
-
- // Execute the instruction
- exec_function=DecodeInstruction(opcode);
- status=(this->*exec_function)(opcode, trace_record, trace_flag);
-
- // If the last instruction was not priviledged then check for trace
- if((status==EXECUTE_OK) && (register_value[SR_INDEX]&T_FLAG))
- status=ProcessException(9);
- }
- }
- else
- {
- if(trace_flag)
- trace_record+="{Mnemonic {CPU is stopped}} ";
- }
- }
-
- if(status==EXECUTE_BUS_ERROR)
- {
- if(ExecuteBusError(opcode, trace_record, trace_flag) != EXECUTE_OK)
- {
- // Oh, no the cpu has fallen and it can't get up!
- processor_state=HALT_STATE;
- if(trace_flag)
- trace_record+="{Mnemonic {Double Bus/Address Error CPU halted}} ";
- }
- }
- else if (status==EXECUTE_ADDRESS_ERROR)
- {
- if(ExecuteAddressError(opcode, trace_record, trace_flag) != EXECUTE_OK)
- {
- // Now, where's that reset button???
- processor_state=HALT_STATE;
- if(trace_flag)
- trace_record+="{Mnemonic {Double Bus/Address Error CPU halted}} ";
- }
- }
- }
- else
- {
- if(trace_flag)
- trace_record+="{Mnemonic {CPU has halted}} ";
- }
-
- // Check the event list
- events.Check();
-
- // Signal if the processor is in a wierd state
- if(processor_state==HALT_STATE)
- {
- return("CPU has halted");
- }
- else if(processor_state==BREAK_STATE)
- {
- processor_state = NORMAL_STATE;
- if(trace_flag)
- return((char*)0);
- else
- return("BREAK instruction");
- }
- else
- return((char*)0);
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // Handle an interrupt request from a device
- ///////////////////////////////////////////////////////////////////////////////
- void m68000::InterruptRequest(BasicDevice* device, int level)
- {
- int interrupt_mask;
-
- // The 68000 has seven levels of interrupts
- if(level>7)
- level=7;
- else if(level<1)
- level=1;
-
- // Get the interrupt mask
- interrupt_mask=(register_value[SR_INDEX] & 0x0700) >> 8;
-
- if((level>interrupt_mask) || (level==7))
- {
- my_interrupt=level;
- my_device=device;
- }
- else
- {
- device->InterruptAcknowledge(1);
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////////
- // Service pending interrupts, set serviceFlag to true iff we
- // are had to service an interrupt
- ///////////////////////////////////////////////////////////////////////////////
- int m68000::ServiceInterrupts(int& serviceFlag)
- {
- if(my_interrupt != -1)
- {
- // Indicate that I had to service an interrupt
- serviceFlag = 1;
-
- int level=my_interrupt;
- int status;
-
- my_interrupt=-1;
-
- // Put the processor into normal state if it's stopped
- if(processor_state==STOP_STATE)
- processor_state=NORMAL_STATE;
-
- // Copy the SR to a temp
- unsigned long tmp_sr = register_value[SR_INDEX];
-
- // Set the Interrupt Mask in SR
- register_value[SR_INDEX] &= 0x0000f8ff;
- register_value[SR_INDEX] |= (level << 8);
-
- // Change to Supervisor mode and clear the Trace mode
- register_value[SR_INDEX] |= S_FLAG;
- register_value[SR_INDEX] &= ~T_FLAG;
-
- // Interrupt has occured so push the PC and the SR
- SetRegister(SSP_INDEX, register_value[SSP_INDEX]-4, LONG);
- if((status=Poke(register_value[SSP_INDEX],
- register_value[PC_INDEX], LONG)) != EXECUTE_OK)
- { return(status); }
-
- SetRegister(SSP_INDEX, register_value[SSP_INDEX]-2, LONG);
- if((status=Poke(register_value[SSP_INDEX], tmp_sr, WORD)) != EXECUTE_OK)
- { return(status); }
-
- // Get the vector number
- long vector=my_device->InterruptAcknowledge(level);
- if(vector==AUTOVECTOR_INTERRUPT)
- vector=24+level;
- else if(vector==SPURIOUS_INTERRUPT)
- vector=24;
-
- // Get the interrupt service routine's address
- unsigned int service_address;
- if((status=Peek(vector*4, service_address , LONG)) != EXECUTE_OK)
- return(status);
-
- // Change the program counter to the service routine's address
- SetRegister(PC_INDEX, service_address, LONG);
- }
- else
- {
- // Indicate that I didn't have to service an interrupt
- serviceFlag = 0;
- }
- return(EXECUTE_OK);
- }
-
-